//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name: wbtdsktp.cpp

Abstract:

Notes:
--*/

#include <windows.h>
#include <wbtshlib.h>
#include "wbtshell.h"
#include "wbtdsktp.h"


#ifdef DEBUG
#include <debug.h>
#endif


const LPWSTR szSetupExeDefault = TEXT("wbtsetup.exe");
const LPWSTR szRegValSetupExe  = TEXT("SetupExe");
const LPWSTR szRegValSetupCmdLine = TEXT("SetupCmdLine");

#define RESET_RESOLUTUION_HOTKEY 100

#define START_TERMINAL_SETUP_4_SETUP 0
#define START_TERMINAL_SETUP_4_SYNC  1
#define START_TERMINAL_SETUP_4_RESET 2

/*++

--*/


CWbtDesktopWindow::CWbtDesktopWindow() {     
   dwTerminalSetupPID = 0;
}


/*++

--*/



CWbtDesktopWindow::~CWbtDesktopWindow() {      
   if (hBrush) DeleteObject(hBrush);
}

/*++

--*/


BOOL
CWbtDesktopWindow::InitInstance(HINSTANCE hInstance) {   
   
   WNDCLASS wndclass;
    
   if(!(hBrush = CreateSolidBrush(RGB(0, 128, 128)))) {
      return FALSE;
      }

   this->hInstance = hInstance;
   ZEROVAR(wndclass);
   
   wndclass.style = CS_HREDRAW | CS_VREDRAW;
   wndclass.lpfnWndProc = (WNDPROC)this->WbtDesktopWindowProc;
   wndclass.cbClsExtra = 0;
   wndclass.cbWndExtra = 0;
   wndclass.hInstance = hInstance;
   wndclass.hIcon = 0;
   wndclass.hCursor = 0;
   wndclass.hbrBackground = hBrush;
   wndclass.lpszMenuName = NULL;
   wndclass.lpszClassName = szDesktopWndClassName;
   
   if (!RegisterClass(&wndclass)) {
      DEBUGMSG(ZONE_ERROR, (TEXT("Desktop registration error (%d).\r\n"), GetLastError()));
      return FALSE;
      } 
     
   hwnd = 
      CreateWindowEx(
          NULL,
          szDesktopWndClassName,
          TEXT("WbtDesktopWindow"),
          WS_VISIBLE,
          0,
          0,
          GetSystemMetrics(SM_CXSCREEN),
          GetSystemMetrics(SM_CYSCREEN),
          NULL,
          NULL,
          hInstance,
          (LPVOID)this
          );
       
   if (!hwnd) {
        DEBUGMSG(ZONE_ERROR,(TEXT("Cannot create desktop window! Error %d.\r\n"), GetLastError));
        return FALSE;
   }   
   DEBUGMSG(ZONE_TRACE,(TEXT("Desktop window created.\r\n")));
   
   ShowWindow(hwnd, SW_SHOW);
   UpdateWindow(hwnd);

   return TRUE;
}


/*++

--*/



LRESULT CALLBACK
CWbtDesktopWindow::WbtDesktopWindowProc(HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
   
   static PWBTDESKTOP pdt = NULL;
   CREATESTRUCT* pcs;

   switch (uMsg) {
      
   case WM_ACTIVATE:
      SetCursor(pdt->hCursor);

      return 0;
   case WM_CREATE:
      pcs = (CREATESTRUCT*)lParam;
      pdt = (PWBTDESKTOP)pcs->lpCreateParams;
      pdt->DesktopSetCursor(IDC_ARROW);

	  pdt->StartTerminalSetup(START_TERMINAL_SETUP_4_SYNC);
	  RegisterHotKey(hwnd,RESET_RESOLUTUION_HOTKEY, MOD_SHIFT|MOD_CONTROL|MOD_ALT|MOD_WIN,VK_F2);

      return 0;

   case WM_DESTROY:
	  UnregisterHotKey(hwnd, RESET_RESOLUTUION_HOTKEY);
	  return 0;

   case WM_SETCURSOR:
      SetCursor(pdt->hCursor);
      return 0;
   
   case WM_HOTKEY:
	   if ( RESET_RESOLUTUION_HOTKEY == (int) wParam )
	   {
         pdt->StartTerminalSetup(START_TERMINAL_SETUP_4_RESET);
	   }

	   return 0;

   case WM_KEYDOWN:

      switch ((INT)wParam) {
      
      case VK_F2:
         pdt->StartTerminalSetup(START_TERMINAL_SETUP_4_SETUP);
         return 0;
      
      default:
         
         break;
      }

   case WBTSHL_SETCURSOR:

      switch (lParam) {
      case CURSOR_ARROW:
         pdt->DesktopSetCursor(IDC_ARROW);
         break;

      case CURSOR_WAIT:
         pdt->DesktopSetCursor(IDC_WAIT);
         break;

      case CURSOR_APPSTRT:
         pdt->DesktopSetCursor(IDC_APPSTARTING);
         break;

      default:
        pdt->DesktopSetCursor(IDC_ARROW); 
      }

      return 0;


   case WBTSHL_TASKMANVKEY:
      pdt->HandlerTaskmanVKey();
      return 0;

   default:
      return DefWindowProc(hwnd, uMsg, wParam, lParam);

   }
   
}


/*++

--*/

VOID
CWbtDesktopWindow::DesktopSetCursor(LPCTSTR lpCursorName) {   
   hCursor = LoadCursor(NULL, lpCursorName);
   SetCursor(hCursor);
}


/*++

--*/

VOID
CWbtDesktopWindow::DesktopShow() {   
   SetForegroundWindow(hwnd);
   }


VOID
CWbtDesktopWindow::TaskmanShow() {   
   
   HWND hwndTaskman;
   
   hwndTaskman = FindWindow(szTaskmanWndClassName, NULL);
   if (hwndTaskman) {
      SendMessage(hwndTaskman, TASKMAN_SHOW, 0, 0);
      }
   }

/*++

--*/


VOID
CWbtDesktopWindow::HandlerTaskmanVKey() {
   
   DEBUGMSG(ZONE_TRACEV,(TEXT("WBTSHELL: WBTSHL_TASKMANVKEY_DOWN message received.\r\n")));
   DesktopShow();
   TaskmanShow();

   if (dwTerminalSetupPID) {
      EnumWindows((WNDENUMPROC)SetForegroundSetup, (LPARAM)this);
      return;
   }
  
}


/*++

--*/


VOID
CWbtDesktopWindow::StartTerminalSetup( int reason) {
   
   DWORD dwThrdId;
   HANDLE hThrd;
   HWND hwndTaskman;
   BOOL bIsHelperRunning;
      
   this->iReasonStartTerminalSetup = reason;

   if (dwTerminalSetupPID) {
      EnumWindows((WNDENUMPROC)SetForegroundSetup, (LPARAM)this);
      return;
   }
   
   if(!(hwndTaskman = FindWindow(szTaskmanWndClassName, NULL)) && 
	    reason != START_TERMINAL_SETUP_4_SYNC ) 
   {
      return;
   }

   if (bIsHelperRunning = (BOOL)SendMessage(hwndTaskman, WBTSHL_ISHELPER_RUNNING, 0, 0)) {
      RETAILMSG(1,(TEXT("DESKTOP: Cannot launch Terminal Setup while Helpers are running.\r\n")));
      return;
   }  

// create a bogus value so setup can't be lauched twice while waiting on the thread to setup
   dwTerminalSetupPID = 0x00001;
   hThrd =
      CreateThread(
         NULL,
         0,
         (LPTHREAD_START_ROUTINE)TerminalSetupProc,
         (LPVOID)this,
         0,
         &dwThrdId
         );

   if (!hThrd) {
      RETAILMSG(1,(TEXT("WBTSHELL: Startup thread failed to start! (%d)\r\n"), GetLastError));
      dwTerminalSetupPID = 0;
   } 
   else
	   CloseHandle(hThrd);


   return;
}


/*++

--*/




DWORD WINAPI
CWbtDesktopWindow::TerminalSetupProc(LPVOID lpvThreadParam) {
   
   BOOL bResult;
   LONG lResult;
   HKEY hKey;
   HWND hwndTaskman, hwndTaskbar;
   DWORD dwSize;
   DWORD dwType;
   PROCESS_INFORMATION pi;
   TCHAR szApplication[MAX_PATH];
   TCHAR szCmdLine[MAX_PATH];
   PWBTDESKTOP pdt = (PWBTDESKTOP)lpvThreadParam;   
         
   DEBUGMSG(ZONE_TRACE,(TEXT("DESKTOP: Enter TerminalSetupProc ...\r\n"))); 

   hwndTaskman = FindWindow(szTaskmanWndClassName, NULL);
   hwndTaskbar = FindWindow(szTaskbarWndClassName, NULL);
   //SetForegroundWindow(pdt->hwnd);
   SetWindowPos(hwndTaskman, pdt->hwnd, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_HIDEWINDOW);
   
   SendMessage(pdt->hwnd, WBTSHL_SETCURSOR, 0, CURSOR_WAIT);   
   

   lResult = 
      RegOpenKeyEx(
          HKEY_LOCAL_MACHINE,
          szRegKeyShellSettings,
          NULL,
          KEY_READ,
          &hKey
          );

   if (lResult != ERROR_SUCCESS) {
      DEBUGMSG(ZONE_ERROR, (TEXT("ERROR: Cannot open \"HKLM\\%s\".\r\n"),szRegKeyShellSettings));
      wcscpy(szApplication, szSetupExeDefault);
      wcscpy(szCmdLine, TEXT(""));
      goto TERMINAL_SETUP_PROC_CREATE_PROCESS;
      }
   
   dwSize = sizeof(szApplication);

   lResult = 
      RegQueryValueEx(
          hKey,
          szRegValSetupExe,
          NULL,
          &dwType,
          (PBYTE)szApplication,
          &dwSize
          );

   if ((lResult != ERROR_SUCCESS)||(dwType != REG_SZ)) {
      wcscpy(szApplication, szSetupExeDefault);
      } 
     
   dwSize = sizeof(szCmdLine);
   lResult = 
      RegQueryValueEx(
          hKey,
          szRegValSetupCmdLine,
          NULL,
          &dwType,
          (PBYTE)szCmdLine,
          &dwSize
          );

   if ((lResult != ERROR_SUCCESS)||(dwType != REG_SZ)) {
      wcscpy(szCmdLine, TEXT(""));
      } 

   if ( pdt->iReasonStartTerminalSetup == START_TERMINAL_SETUP_4_SYNC)
   {
	  wcscpy(szCmdLine, TEXT("SYNC"));
   }

   if ( pdt->iReasonStartTerminalSetup == START_TERMINAL_SETUP_4_RESET)
   {
	  wcscpy(szCmdLine, TEXT("RESET"));
   }

   RegCloseKey(hKey);
        
TERMINAL_SETUP_PROC_CREATE_PROCESS:      
   DEBUGMSG(ZONE_TRACE,(TEXT("DESKTOP: CreateProcess(\"%s\", \"%s\", ...)\r\n"), szApplication, szCmdLine));

   bResult = 
      CreateProcess(
         szApplication,
         szCmdLine,
         NULL,
         NULL,
         FALSE,
         NULL,
         NULL,
         NULL,
         NULL,
         &pi
         );
   SendMessage(pdt->hwnd, WBTSHL_SETCURSOR, 0, CURSOR_ARROW);
   
   if (bResult) {
      pdt->dwTerminalSetupPID = pi.dwProcessId;
      WaitForSingleObject(pi.hProcess, INFINITE);            
   }
   else {
   CreateProcessError(pdt->hInstance, pdt->hwnd, szApplication, GetLastError());
   }

   pdt->dwTerminalSetupPID = 0;      
   
   DEBUGMSG(ZONE_TRACE,(TEXT("DESKTOP: Exit TerminalSetupProc.\r\n")));    
   SendMessage(hwndTaskman, WBTSHL_CONFIG_UPDATE, 0, 0);
   SendMessage(hwndTaskbar, WBTSHL_CONFIG_UPDATE, 0, 0);
//   SetForegroundWindow(pdt->hwnd);
   SetWindowPos(hwndTaskman, pdt->hwnd, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
   SetForegroundWindow(hwndTaskman);
   ExitThread(0);
   return 0;
}


/*++
 
--*/


BOOL CALLBACK
CWbtDesktopWindow::SetForegroundSetup(HWND hwnd, LPARAM lParam) {

   PWBTDESKTOP pdt = (PWBTDESKTOP)lParam;
   DWORD dwProcessId;
      
   GetWindowThreadProcessId(hwnd, &dwProcessId);
   
   if ((dwProcessId == pdt->dwTerminalSetupPID)&&(IsWindowVisible(hwnd))) {
      pdt->DesktopShow();
      SetForegroundWindow(hwnd);
      return FALSE;
   }

   return TRUE;
}


